﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using DiagramDesigner.BusinessModelObject;
using System.Reflection;
using System.ComponentModel;
using DiagramDesigner.Utils;

namespace DiagramDesigner.Controls
{
    /// <summary>
    /// Interaction logic for UCProperties.xaml
    /// </summary>
    public partial class UCProperties
    {
        #region Properties
        BaseField BaseField
        {
            get;
            set;
        }
        DesignerItem DesgItem
        {
            get;
            set;
        }
        #endregion

        #region Constructor
        public UCProperties()
        {
            InitializeComponent();
        }
        #endregion

        #region Methods
        void CreateRow<T>(T obj, PropertyInfo p)
        {
            // Obteniendo la descripción de la propiedad del objeto
            var descAtrribute = Extensions.GetAttributes<DescriptionAttribute>(p);
            if (descAtrribute == null) return;

            // Insertando un row definition
            var rd = new RowDefinition { Height = new GridLength(30) };
            gridProperty.RowDefinitions.Add(rd);

            var description = descAtrribute.Description;
            CreateLabel(description);

            var ctrl = CreateControl(obj, p);
            Grid.SetRow(ctrl, gridProperty.RowDefinitions.Count - 1);
            Grid.SetColumn(ctrl, 1);

            gridProperty.Children.Add(ctrl);
        }
        void CreateLabel(string label)
        {
            var txb = new TextBlock { Text = label };
            Grid.SetRow(txb, gridProperty.RowDefinitions.Count - 1);
            Grid.SetColumn(txb, 0);

            gridProperty.Children.Add(txb);
        }
        UIElement CreateControl<T>(T obj, PropertyInfo p)
        {
            var tp = Extensions.GetAttributes<TypePropertyAttribute>(p);
            if (tp == null) return null;

            UIElement ctrl = null;
            switch (tp.Control)
            {
                case TypeControl.ComboBoxContol: ctrl = CreateComboBox(obj, p); break;
                case TypeControl.TextBoxControl: ctrl = CreateTextBox(obj, p); break;
                case TypeControl.TextAndListControl: ctrl = CreateTextAndList(obj, p); break;
            }

            return ctrl;
        }
        void CleanProperties()
        {
            gridProperty.Children.Clear();
            gridProperty.RowDefinitions.Clear();
        }

        public void CleanProperties(bool isClean)
        {
            if (isClean)
            {
                gridProperty.Children.Clear();
                gridProperty.RowDefinitions.Clear();
            }
        }

        #region Create Controls
        ComboBox CreateComboBox<T>(T obj, PropertyInfo p)
        {
            if (!p.PropertyType.IsEnum) return null;

            var cbo = new ComboBox { Tag = p.Name };
            cbo.SelectionChanged += LstSelectionChanged;

            var selectedText = p.GetValue(obj, null).ToString();

            foreach (var s in Enum.GetNames(p.PropertyType))
            {
                if ((BaseField is MedidaEspacial || BaseField is MedidaNoEspacial) && s == "Varchar2") continue;

                var item = new ComboBoxItem { Content = ((Enum)Enum.Parse(p.PropertyType, s, true)).GetDescription() };
                cbo.Items.Add(item);

                if (string.Equals(s, selectedText, StringComparison.OrdinalIgnoreCase))
                    cbo.SelectedItem = item;
            }

            return cbo;
        }
        TextBox CreateTextBox<T>(T obj, PropertyInfo p)
        {
            var txt = new TextBox { Tag = p.Name };
            txt.TextChanged += TxtTextChanged;
            var getValue = p.GetValue(obj, null);
            if (getValue != null) txt.Text = getValue.ToString();

            return txt;
        }
        Grid CreateTextAndList<T>(T obj, PropertyInfo p)
        {
            var td = (TypeData)p.GetValue(obj, null);

            var gridControl = new Grid { Tag = p.Name };
            gridControl.RowDefinitions.Add(new RowDefinition());
            var i = 0;
            foreach (var pi in td.GetType().GetProperties())
            {
                var width = (i == 0)?80:30;
                gridControl.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(width) });
                var element = CreateControl(td, pi);
                Grid.SetRow(element, 0);
                Grid.SetColumn(element, i);
                gridControl.Children.Add(element);
                i++;
            }

            #region mostrando los textboxes segun el valor del dropdown
            var cbo = (ComboBox) gridControl.Children[0];

            ShowScaleText(cbo,false);
            cbo.SelectionChanged += UCProperties_SelectionChanged;
            #endregion
            
            return gridControl;
        }
        void ShowScaleText(ComboBox cbo, bool pasado)
        {
            var txt = ((Grid) cbo.Parent).Children[2] as TextBox;
            if(cbo.Text == string.Empty)return;
            var typedato = (TypeDatos) Enum.Parse(typeof (TypeDatos), cbo.Text, true);

            if (txt == null) return;

            if (pasado)
                txt.Visibility = (typedato != TypeDatos.Varchar2) ? Visibility.Hidden : Visibility.Visible;
            else
                txt.Visibility = (typedato == TypeDatos.Varchar2 ) ? Visibility.Hidden : Visibility.Visible;
        }

        void UCProperties_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ShowScaleText((ComboBox)sender, true);
        }

        void LstSelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var cbo = (ComboBox)sender;
            if (cbo.SelectedItem==null || string.IsNullOrEmpty(((ComboBoxItem)cbo.SelectedItem).Content.ToString())) return;

            var obj = BaseField ?? (object)DesgItem.Item;

            var pi = obj.GetType().GetProperty(cbo.Tag.ToString());
            
            //if (pi == null) pi = obj.GetType().GetProperty("DataType");
            if (pi == null)
            {
                var tagValue = cbo.Parent == null ? cbo.Tag.ToString() : ((Grid) cbo.Parent).Tag.ToString();
                pi = obj.GetType().GetProperty(tagValue);
                if(pi==null && BaseField != null)
                {
                    var bObj = Convert.ChangeType(BaseField, BaseField.GetType());
                    pi = bObj.GetType().GetProperty("DataType");
                }
                if (pi != null)
                {
                    var tp = (TypeData)pi.GetValue(obj, null);
                    pi = tp.GetType().GetProperty(cbo.Tag.ToString());
                    obj = tp;
                }
            }

            if (pi != null)
            {
                var newEnumValue = Enum.Parse(pi.PropertyType, (cbo.SelectedIndex.ToString()));
                pi.SetValue(obj, newEnumValue, null);
            }

            if (obj is TypeData && BaseField != null)
            {
                var bObj = Convert.ChangeType(BaseField, BaseField.GetType());
                pi = bObj.GetType().GetProperty("DataType");
                pi.SetValue(bObj, obj, null);
            }

            // seteando la parte grafica
            ChangeGraphics((ComboBox)sender);
        }
        void TxtTextChanged(object sender, TextChangedEventArgs e)
        {
            var txt = (TextBox)sender;
            if (string.IsNullOrEmpty(txt.Text)) return;

            var obj = BaseField ?? (object)DesgItem.Item;

            var pi = obj.GetType().GetProperty(txt.Tag.ToString());
            if (pi == null && txt.Parent != null)
            {
                pi = obj.GetType().GetProperty(((Grid)txt.Parent).Tag.ToString());
                var tp = (TypeData)pi.GetValue(obj, null);
                pi = tp.GetType().GetProperty(txt.Tag.ToString());
                obj = tp;
            }

            if (pi == null) return;
            int valor;
            if (int.TryParse(txt.Text, out valor) && Extensions.IsInteger(pi.GetValue(obj,null).ToString()))
                pi.SetValue(obj, valor, null);
            else
            {
                try
                {
                    pi.SetValue(obj, txt.Text, null);
                }
                catch
                {
                    var d = Extensions.GetAttributes<DefaultValueAttribute>(pi);
                    pi.SetValue(obj,d.Value,null);
                }
            }

            if(obj is TypeData && BaseField!=null)
            {
                var bObj = Convert.ChangeType(BaseField, BaseField.GetType());
                pi = bObj.GetType().GetProperty("DataType");
                pi.SetValue(bObj, obj, null);
            }

            ChangeGraphics((TextBox)sender);
        }
        #endregion
        ImageSource GenerateImageSource(string tipo)
        {

            var imgTipo = DesignerCanvas.mt_DevolverImagen(tipo);
            var myUriTimeSurface = new Uri(imgTipo, UriKind.RelativeOrAbsolute);
            var imageTimeSurface = new BitmapImage();
            imageTimeSurface.BeginInit();
            imageTimeSurface.UriSource = myUriTimeSurface;
            imageTimeSurface.EndInit();

            return imageTimeSurface;
        }

        void ChangeGraphics(ComboBox cbo)
        {
            var tipo = DesgItem.Content.GetType();
            ListView lst = null;

            switch(cbo.Tag.ToString())
            {
                case "AggregationFunction": 
                    if (tipo == typeof(GUIFactTable)) lst = ((GUIFactTable)DesgItem.Content).lstview;
                    if (lst != null)
                    {
                        var item = (lst.Items.Count == 1) ? lst.Items[0] : lst.SelectedItem;
                        ((MeasureAttribute)item).FunctionAgregation =
                            ((ContentControl)cbo.SelectedItem).Content.ToString();
                        lst.Items.Refresh();
                    }
                    break;
                case "Key":
                    if (tipo == typeof(GUIFactTable)) lst = ((GUIFactTable)DesgItem.Content).lstview;
                    if (tipo == typeof(GUILSLevel)) lst = ((GUILSLevel)DesgItem.Content).lstview;
                    if (tipo == typeof(GUILevel)) lst = ((GUILevel)DesgItem.Content).lstview;

                    if (lst != null)
                    {
                        var item = (MeasureAttribute)lst.SelectedItem;
                        if (item == null && lst.Items.Count == 1)
                            item = (MeasureAttribute)lst.Items[0];
                        if (item != null)
                            item.ElementID = cbo.SelectedIndex;
                        lst.Items.Refresh();
                    }
                    break;
                case "Geometry":
                    Image imgSource;
                    var itemSelected = (TypeGeometry)Enum.Parse(typeof(TypeGeometry), cbo.SelectedIndex.ToString());

                    if (tipo == typeof(GUILSLevel))
                    {
                        imgSource = ((GUILSLevel)DesgItem.Content).imgSource;
                        var imgTipo = ((LSLevelModel)DesgItem.Item).HasTemporalImage
                                          ? "Time" + itemSelected
                                          : itemSelected.ToString();
                        imgSource.Source = GenerateImageSource(imgTipo);
                    }
                    if (tipo == typeof(GUILevel))
                    {
                        imgSource = ((GUILevel)DesgItem.Content).imgSource;
                        var imgTipo = ((LevelModel)DesgItem.Item).HasTemporalImage
                                          ? "Time" + itemSelected
                                          : itemSelected.ToString();
                        imgSource.Source = GenerateImageSource(imgTipo);
                    }
                    break;
            }
        }
        void ChangeGraphics(TextBox txt)
        {
            var tipo = DesgItem.Content.GetType();
            if(txt.Tag.ToString() == "Name" && BaseField == default(BaseField))
            {
                if (tipo == typeof(GUIFactTable)) ((GUIFactTable)DesgItem.Content).lblName.Content = txt.Text;
                if (tipo == typeof(GUILevel)) ((GUILevel)DesgItem.Content).lblName.Content = txt.Text;
                if (tipo == typeof(GUILSLevel)) ((GUILSLevel)DesgItem.Content).lblName.Content = txt.Text;
                if (tipo == typeof(GUICriterion)) ((GUICriterion)DesgItem.Content).lblName.Content = txt.Text;
            }
            if(txt.Tag.ToString()=="Name" && BaseField != default(BaseField))
            {
                ListView lst=null;

                if (tipo == typeof(GUIFactTable)) lst = ((GUIFactTable)DesgItem.Content).lstview;
                if (tipo == typeof(GUILevel)) lst = ((GUILevel)DesgItem.Content).lstview;
                if (tipo == typeof(GUILSLevel)) lst = ((GUILSLevel)DesgItem.Content).lstview;

                if (lst != null)
                {
                    //if (lst.Items.Count==1) lst.SelectedIndex = 0;
                    var item = (lst.Items.Count == 1) ? lst.Items[0] : lst.SelectedItem;
                    if (item != null)
                    {
                        ((MeasureAttribute) item).ElementName = txt.Text;
                        lst.Items.Refresh();
                    }
                }
            }
        }


        public void ShowProperties<T>(T model) where T : DesignerItem
        {
            DesgItem = model;
            BaseField = default(BaseField);
            CleanProperties();

            var properties = model.Item.GetType().GetProperties();
            foreach (var property in properties)
                CreateRow(model.Item, property);
        }
        public void ShowProperties<T, TK>(T model, TK p) where T : DesignerItem
        {
            DesgItem = model;
            BaseField = p as BaseField;
            CleanProperties();

            var properties = p.GetType().GetProperties();
            foreach (var property in properties)
                CreateRow(p, property);
        }
        public T GetObject<T>()
        {
            var obj = BaseField ?? (object)DesgItem.Item;
            return (T)obj;
        }

        #endregion
    }
}
